/* 
Copyright (c) 2004,2005, 2006, 2007, 2008 University of Illinois 

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.

3. The name of the author may not be used to endorse or promote products
   derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/** @fileoverview
 * Essentially main.c, the repository of extension init, utility, preference handling, and trivial user functionality.  
 */

/*
   The init needs to be called when the main window has loaded.
   If it were called at script load time, SeaMonkey would have a fit.
   This concept was derived from WebDeveloper
*/
/*
function(?= ) ([^<]*?)\(
$1: function(
 */
AccessibilityExtension.ns(function() { with (AccessibilityExtension.LIB) {
//	AccessibilityExtension.LIB.libFunctionCount(AccessibilityExtension.LIB, 'accessibilityext');
//	if (AccessibilityExtension.LIB.accessext_openToolbarButton) alert ('  accessext_openToolbarButton exists')

	var AE = AccessibilityExtension.ns;  
	
	// FIXME: Good idea defining the constant, bad idea that we still hardcode the string elsewhere
	var accessext_userStylesheet = null;
	var accessext_initialized = false;
	var accessextKeybindings = null;
	var renamedNodes = Array();//Used to keep track of what nodes get renamed in certain functions
	var accessext_activeDoc = null;
	var accessext_menu_fixed = false;
	var accessext_initialSettingsHash = new Object();
	
	const ae_pref_document = 1, ae_pref_tab = 2, ae_pref_global = 3;
	
	/** Initialize extension.  Called when extensionfuly loads.
	 * @returns None
	 */
	
	/** @class <p>Manages tracking information for documents on a per-document basis (Untested, Unfinished).
	 * Seems to track by embedding informative elements (considered properties) in the document.
	 * The information is embedded in the LINK tag.</p>
	 * <p>Not sure why the information must be stored in the document itself when we have this persistant 
	 * tracking object; perhaps it helps deal with the situation where a document is returned to in the course of navigation?
	 * This would force memory management of actual preferences and values on the browser instead of us.</p>
	 * <p>This is probably not desirable; when the per-tab preferences is online, this kind of code should be removed.</p>
	 * @constructor
	 * @param doc DOM document to track?
	 * @returns None
	 */
	function accessext_Document(doc) {
	   this.doc = doc;
	   if (this.doc) {
	      var head = doc.getElementsByTagName('head');
	      if (head.length == 1) {
	         this.head = head[0];
	      }
	   }
	}
	accessext_Document.prototype = { 
			   /** A reference encapsulating the DOM document node */
			   doc : null,
			   /** A reference to the document header if the document has one, otherwise null */
			   head : null, 
			   /**
			    * Has a particular preference been set in this document?
			    * @param pref Preference String
			    * @returns False if this document does not contain the preference, otherwise true.
			    * @type Boolean
			    */
			   hasPref : function(pref) { 
			      if (this.doc == null) {
			         return false;
			      } else if (this.doc.getElementById('aepref-' + pref) == null) {
			         return false;
			      }
			      //TODO: Check persistent
			      return true;
			   },
			   /**
			    * Removes the specified preference from the document.
			    * @param pref Preference String
			    * @returns True on success, false on failure
			    * @type Boolean
			    */
			   removePref : function(pref) {
			      var e;
			      try {
			         e = this.doc.getElementById('aepref-' + pref);
			         e.parentNode.removeChild(e);
			      } catch (ex) {
			         return false;
			      }
			      return true;
			   },
			   /**
			    * Adds the given preference to the document.
			    * @param pref Preference String
			    * @returns True if preference added, False if unable to add preference.
			    * @type Boolean
			    */
			   addPref : function(pref) {
			      var e;
			      e = this.doc.createElement('link');
			      e.setAttribute('id','aepref-' + pref);
			      e.setAttribute('href','');
			      if (this.head) {
			         this.head.appendChild(e);
			      } else {
			    	  accessext_consoleDump("Can't add preference to document, since document does not contain a <HEAD> element");
			         return false;
			      }
			      return true;
			   },
			   /**
			    * Sets a boolean preference condition in the document.
			    * @param pref Preference String
			    * @param value Boolean indicating whether to set or unset the preference
			    * @returns True on success, False on failure
			    */
			   setBoolPref : function(pref,value) {
			      try {
			         var e;
			         if (this.hasPref(pref) && (value == false)) {
			            this.removePref(pref);
			         } else {
			            e = this.addPref(pref);
			            // FIXME: What's the point of the below code?  addPref returns a boolean!?
			            // ... I think he was trying to mark the LINK as a boolean preference.
			            if (e) {
			               e.rel='accessext.pageBoolPref';
			            }
			         }
			         //If persistent is enabled, set globally
			      } catch (ex) {
			         return false;
			      }
			      return true;
			   }
			};
	
//	window.addEventListener("load", accessext_initialize, true);

AccessibilityExtension.LIB.extend(AccessibilityExtension.LIB,
{
	accessext_initialize: function(event) {
	
	   accessext_detailLog("called accessext_initialize");
	
	   var preferencesService = getAccessextPrefService();
	   var val = false;
	   var element = null;
	   var str = "";
	   
	   accessextKeybindings = newAccessextKeybindingManager();
	
	   accessext_setupPreferences();
	
	   accessext_userStylesheet = preferencesService.getCharPref("styles.userStylesheet.text");
	
	   /* Derived from webdeveloper */
	   try {
		   if (getBrowser && getBrowser()) {
		      try {
		         getBrowser().mTabBox.addEventListener("select", accessext_tabSelect, true);
		      } catch(exception) {
		    	  accessext_consoleDump(exception);
		      }
		   }
	   } catch (ex) {
			accessext_consoleDump('accessext_initialize exception: ', ex);
	   }
	   
	   try {
	      window.removeEventListener("load", accessext_pageLoad, true);
	   } catch(exception) {
		   accessext_consoleDump('accessext_initialize exception: ',exception);
	   }
	   
	   try {
	      window.removeEventListener("unload", accessext_pageUnload, true);
	   } catch(exception) {
		   accessext_consoleDump('accessext_initialize exception: ',exception);
	   }
	   
	   try {
	      window.removeEventListener("focus", accessext_windowFocus, false);
	   } catch(exception) {
		   accessext_consoleDump('accessext_initialize exception: ',exception);
	   }
	   
	   try {
	      gBrowser.addEventListener("load", accessext_pageLoad, true); //FF3 update
	      gBrowser.addEventListener("load", listenForFAE, true);      
	   } catch(exception) {
		   accessext_consoleDump('accessext_initialize exception: ',exception);
	   }
	   try {
	      //window.addEventListener("unload", accessext_pageUnload, true);
		  //SMF accessext_ToBeUninstalled()
	      window.addEventListener("unload", accessext_pageUnload, false);
	  } catch(exception) {
		  accessext_consoleDump('accessext_initialize exception: ',exception);
	   }
	   
	   try {
	      window.addEventListener("focus", accessext_windowFocus,false);
	   } catch(exception) {
		   accessext_consoleDump('accessext_initialize exception: ',exception);
	   }
	   
	   try   {
	       window.removeEventListener("load", accessext_initialize, true);
	   } catch(exception) {
		   accessext_consoleDump('Failed to unload accessext_initialize: ', exception);
	   }
	
	   /* var Visualize = {
	     FAEListener: function(evt) {
		   var dialogName = evt.target.getAttribute("visualize");
		   dialogName = dialogName.substring(0, dialogName.indexOf('.'));
		   openAndReuseOneTabPerURL(evt.target.getAttribute("url"));
		   accessext_open_window(dialogName);
		}
	   }
	   window.addEventListener("FFAccessibilityExtEvent", function(e) { Visualize.FAEListener(e); }, false, true);
	   */
	},
	
	/** Returns the preference for extension modification of document scope.
	 * Should be something like 'document', 'tab', or 'global', but it depends on where it gets set elsewhere.
	 * FIXME: Acceptable values should be encapsulated in an object or at least in a global array.
	 * @returns Persistance preference indicatior 
	 * @type String
	 */
	 accessext_getActivePreferenceMode: function() {
	   var pref = getAccessextPrefService();
	   if (pref.prefHasUserValue("options.prefPersistence")) {
	      var val = pref.getCharPref("options.prefPersistence");
	      return val;
	   }
	   return 'document';
	},
	
	/** Toggles browser's type-ahead-find via preferences
	 * @returns None
	 */
	accessextToggleTypeAheadFind: function() {
	   var pref = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("");
	   pref.setBoolPref("accessibility.typeaheadfind", !pref.getBoolPref("accessibility.typeaheadfind")); 
	},
	
	/** Abstracts getting a boolean preference for the currently interesting (active page or global) resource.
	 * FIXME: This doesn't really do anything important, now.  It is written to return the preference for the 
	 * active document when the per-document preference object system is being used; which it isn't.
	 * @param pref Preference String
	 * @returns State of preference
	 * @type Boolean
	 */
	accessext_getManagedBoolPref: function(pref) {
	   switch (accessext_getActivePreferenceMode()) {
	      case 'document'://doc
	         if (null == accessext_activeDoc) {
	            return false;
	         } else {
	            return accessext_activeDoc.hasPref(pref);
	         }
	      break;
	      case 'tab'://tab
	         //NOT USED
	      break;
	      case 'global'://global
	         var prefSvc = getAccessextPrefService();
	         return pref.getBoolPref(pref);
	      break;
	   }
	   return false;
	},
	
	/** Abstracts detecting whether a particular boolean preference for the currently interesting (active page or global) resource exists.
	 * @see #accessext_getManagedBoolPref
	 * @param pref Preference String
	 * @returns True if preference exists
	 * @type Boolean
	 */
	accessext_hasManagedBoolPref: function(pref) {
	   switch (accessext_getActivePreferenceMode()) {
	      case 1://doc
	         if (null == accessext_activeDoc) {
	            return false;
	         } else {
	            return accessext_activeDoc.hasPref(pref);
	         }
	      break;
	      case 2://tab
	         //NOT USED
	      break;
	      case 3://global
	         var prefSvc = getAccessextPrefService();
	         return pref.prefHasUserValue(pref);
	      break;
	   }
	   return false;
	},
	
	/** Abstracts setting a particular boolean preference for the currently interesting (active page or global) resource.
	 * FIXME: Not implemented at all
	 * @see #accessext_getManagedBoolPref
	 * @param pref Preference String
	 * @returns None
	 */
	accessext_setManagedBoolPref: function(pref) {
	
	},
	
	/** Creates a preference object for the currently activated document.
	 * Called on page load and tab select, currently.
	 * @param doc The relevant DOM document
	 * @returns None
	 */
	accessext_activateDocument: function(doc) {
	   accessext_activeDoc = new accessext_Document(doc);
	},
	
	/** Detects if the browser is Firefox
	 * @returns True if this browser identifies itself as Firefox, false if not.
	 */
	accessext_is_firefox: function() {
	   return (navigator.userAgent.toUpperCase().indexOf('FIREFOX') >=0);
	},
	
	/** Detects if the browser is not Firefox 1.0?
	 * Perhaps if the browser is firefox but is not Firefox 1.0 then it is automatically 1.5 or greater?
	 * @returns True if this browser is not Firefox 1.0
	 */
	accessext_is_firefox15OrGreater: function() {
	      return (navigator.userAgent.toUpperCase().indexOf('FIREFOX/1.0') < 0);
	},
	
	/** A workaround to fix the menu appearance of the browser menubar on OS X.
	 * @returns None
	 */
	accessext_menuFix: function() {
	   var menu = document.getElementById('accessext-menu');
	   var tools = document.getElementById('tasksMenu');
	   //var nav = document.getElementById('accessext-mainmenu-navigation');
	   //if (menu != null && tools != null && nav != null) {
	   if (menu != null && tools != null) {
	
	      //nav.parentNode.removeChild(nav);
	      //accessext_DOM_insertAfter(tools,nav);
	      accessext_DOM_insertAfter(tools);
	
	      menu.parentNode.removeChild(menu);
	      accessext_DOM_insertAfter(tools,menu);
	
	      accessext_menu_fixed = true;
	   }
	},
	
	/** 
	 * Format Page with AccessExtSettings (such as if show text equivalents is checked, when a document is opened the test equivalents are shown.
	 * Called on every page load.
	 */
	accessext_enablePersistentOptions: function(doc) {
	   
	   var accessext_features = new AccessibilityExtension.LIB.accessextFeatures();
	   var features = accessext_features.getListOfFeatures();
	   for (var i = 0; i < features.length; i ++) {
	      var feature = accessext_features.getFeature(features[i]);
	      //   accessext_consoleDump('feature: ' + feature.name + ' prefDrive:' + feature.prefDriven  + ' '  + feature.getToggleStatus());
	     if ((accessext_getActivePreferenceMode() == 'global' || feature.prefDriven) && feature.getToggleStatus() == true) {
	     //    accessext_consoleDump('current state for ' + feature.name + ' set to true');
				accessext_toggle_feature(feature.name,feature.getToggleStatus(),true,doc);
	      } else if (feature.initialState == true) {
	         //accessext_consoleDump('Initial state for ' + feature.name + ' set to true');
	         feature.updateToggle(true);
	      }
	   }
	},
	
	/** Called every time tabSelect, windowFocus, or pageLoad to execute feature modifications on the current page and menu state.
	 * Note, this is not efficient.
	 * @returns None
	 */
	accessext_updateMenus: function() {
		try
		{
		   if (!accessext_activeDoc) {//Bugfix for Seamonkey
		       return;
		   } 
		   var preferencesService = getAccessextPrefService();
		    
		   //TODO: Convert to radio
		   accessext_switchPrefPersistenceMode(preferencesService.getCharPref("options.prefPersistence"));
		   accessext_switchPrefStandard(currStandard());
		   
		   var accessext_features = new AccessibilityExtension.LIB.accessextFeatures();
		   var features = accessext_features.getListOfFeatures();
		   var status = false;
		   var feature = null;
		   for (var i = 0; i < features.length; i ++) {
		      feature = accessext_features.getFeature(features[i]);
		      switch (feature.type) {
		         case 'toggle' :
		            if (accessext_getActivePreferenceMode() != 'global') {
		               if (feature.prefDriven) {
		                  status = feature.getToggleStatus();
		               } else if (accessext_hasManagedBoolPref(feature.prefStr)) {
		                  status = accessext_getManagedBoolPref(feature.prefStr);
		               } else {
		                  status = feature.initialState;
		               }
		                feature.updateToggle(status);
		            } else if (accessext_getActivePreferenceMode() == 'global') {
		               feature.updateToggle(feature.getToggleStatus());
		            }
		         break;
		      }
		   }
		//accessext_consoleDump('updateMenus END');
		} catch (exc) {
			accessext_consoleDump(exc);
		}
	},
	
	/** Initializes the preferences for features.
	 * FIXME: This needs to go work through the Feature class and not duplicate the strings!
	 * @returns None
	 */
	accessext_setupPreferences: function() {
	   accessext_detailLog("called accessext_setupPreferences");
	   var prefService = getAccessextPrefService();
	   //Initalize preferences to default values
	   var boolPrefs = new Array("images.hide",
	      "textequivall.hide",
	      "objects.hide",
	      "images.replaceWithAlt",
	      "styles.highcontrast",
	      "styles.highcontrast2",    
	      "styles.userStylesheet.enable",
	      "accesskeys.disable",
	      "options.events.disable",
	      "options.expandAbbr",
	      "menus.hideNavigationMainMenu",
	      "disableMetaRefresh",
	      "disableScripting",     
	      "standards.newWindow",
	      "standards.useDom",
	      "fae.mergeFrames",
	      "fae.includeIframes");
	   var pref;
	   for(prefNum in boolPrefs) {
	      if (!prefService.prefHasUserValue(boolPrefs[prefNum])) {
	         prefService.setBoolPref(boolPrefs[prefNum],false);
	      }
	   }
	   
	   if (!prefService.prefHasUserValue("styles.author.css.enabled")) {
	      prefService.setBoolPref("styles.author.css.enabled",true);
	   }
	    if (!prefService.prefHasUserValue("styles.css.tags.enabled")) {
	      prefService.setBoolPref("styles.css.tags.enabled",true);
	   }
	   if (!prefService.prefHasUserValue("styles.css.tables.enabled")) {
	      prefService.setBoolPref("styles.css.tables.enabled",true);
	   }
	  
	   if (!prefService.prefHasUserValue("showMenus")) {
	      prefService.setBoolPref("showMenus",true);
	   }
	   
	   if (!prefService.prefHasUserValue("keyboardnav.mode")) {
	      prefService.setCharPref("keyboardnav.mode","off");
	   }
	
	   if(!prefService.prefHasUserValue("styles.userStylesheet.text")) {
	      prefService.setCharPref("styles.userStylesheet.text", "");
	   }
	   
	   if(!prefService.prefHasUserValue("options.prefPersistence")) {
	      prefService.setCharPref("options.prefPersistence",'document');
	   }
	   if(!prefService.prefHasUserValue("accessext.options.highlight.color")) {
	      prefService.setCharPref("accessext.options.highlight.color", "yellow");
	   }
	   if(!prefService.prefHasUserValue("accessext.options.highlight.border")) {
	      prefService.setCharPref("accessext.options.highlight.border", "medium double rgb(250,0,255)");
	   }
	   
	   // reset validator keybinding prefs for ctrl-v stealing bug. should be removed eventually.
	   prefService.setCharPref("key.standards.w3c.cssValidator", "W");
	   prefService.setCharPref("key.standards.w3c.htmlValidator", "W");
	   /*
	    * SMF Set the default keybindings the first time the user starts the AccessExt Add-On.
	    * the following does not work
	    *    if(!prefService.prefHasUserValue("accessext.keybindings.reset.onload")) {prefService.setBoolPref("accessext.keybindings.reset.onload", true);}
	    */
	},
	
	accessext_handle_toc_reset: function(doc) {
	   var accessext_features = new AccessibilityExtension.LIB.accessextFeatures();
	   accessext_handle_TOChighlight('all',false,doc);
	   /* Reset all features as well */
	   if (accessext_features.getFeature('toc-showAll').getToggleStatus() == true) {
	      accessext_toggle_feature('toc-showAll',false,false,doc);
	   }
	   if (accessext_features.getFeature('toc-showMain').getToggleStatus() == true) {
	      accessext_toggle_feature('toc-showMain',false,false,doc);
	   }
	   if (accessext_features.getFeature('toc-showSecondary').getToggleStatus() == true) {
	      accessext_toggle_feature('toc-showSecondary',false,false,doc);
	   }
	   if (accessext_features.getFeature('toc-showBanner').getToggleStatus() == true) {
	      accessext_toggle_feature('toc-showBanner',false,false,doc);
	   }
	   if (accessext_features.getFeature('toc-showNavigation').getToggleStatus() == true) {
	      accessext_toggle_feature('toc-showNavigation',false,false,doc);
	   }
	},
	
	/* Temporary */
	accessext_handle_toc_all: function(checked,doc) {
	   if (checked) {
	      accessext_handle_toc_reset(doc);
	   }
	},
	
	accessext_handle_toc_main: function(checked,doc) {
	   if (checked) {
	      accessext_handle_toc_reset(doc);
	   }
	   return accessext_handle_TOChighlight('main',checked,doc);
	},
	accessext_handle_toc_secondary: function(checked,doc) {
	   if (checked) {
	      accessext_handle_toc_reset(doc);
	   }
	   return accessext_handle_TOChighlight('secondary',checked,doc);
	},
	accessext_handle_toc_navigation: function(checked,doc) {
	   if (checked) {
	      accessext_handle_toc_reset(doc);
	   }
	   return accessext_handle_TOChighlight('navigation',checked,doc);
	},
	accessext_handle_toc_banner: function(checked,doc) {
	   if (checked) {
	      accessext_handle_toc_reset(doc);
	   }
	   return accessext_handle_TOChighlight('banner',checked,doc);
	},
	
	/* Temporary fix */
	// Not so temporary :)  I think this was done to interface between the method signature required by the 
	// toggle feature callback and the actual that does the work.  Not a problem, but this code should be 
	// relocated.
	accessext_handle_events_toggle_mouse: function(checked,doc) {
	   return accessext_handle_events('mouse',checked,doc);
	},
	
	accessext_handle_events_toggle_window: function(checked,doc) {
	   return accessext_handle_events('window',checked,doc);
	},
	
	accessext_handle_events_toggle_forms: function(checked,doc) {
	   return accessext_handle_events('forms',checked,doc);
	},
	
	accessext_handle_highcontrast: function(checked,doc) {
		return accessext_handle_styles_setStylesheet('highcontrast',checked,doc);
	},
	accessext_handle_highcontrast2: function(checked,doc) {
	   return accessext_handle_styles_setStylesheet('highcontrast2',checked,doc);
	},
	
	/** Opens the appropriate dialog window
	 * @param name String - a string that maps to the appropriate .xul dialog definition
	 * @returns True if name is recognized and False if not.
	 * @type boolean
	 */
	accessext_open_window: function(name) {
	   var id = null;
	   var url = null;
	   var style = "resizable=yes";
	   switch (name) {
	      // FIXME: will be superceeded by keyboardshortcuts; remove when that functionality is complete
	      case 'keyboardshortcuts':
	         id = "accessext-keyboardshortcuts";
	         url = "chrome://accessext/content/keyboardshortcuts.xul";
	      break;
	      case 'keyboardenhancements':
	         id = "accessext-keyboardenhancements";
	         url = "chrome://accessext/content/keyboardenhancements.xul";
	      break;
	      case 'configuration':
	         id = "accessext-configuration";
	         url = "chrome://accessext/content/configuration.xul";
	      break;
	      case 'listoflinks':
	      case 'links':
	      case 'accessext-form-list-links':
	        id = "accessext-form-list-links";
	         url = "chrome://accessext/content/listoflinks.xul";
	      break;
	      case 'listofheaders':
	      case 'headers':
	      case 'accessext-form-list-headers':
	         id = "accessext-form-list-headers";
	         url = "chrome://accessext/content/listofheaders.xul";
	      break;
	      case 'listofaccesskeys':
	      case 'accesskey':
	      case 'accessext-form-list-accesskeys':
	         id = "accessext-form-list-accesskeys";
	         url = "chrome://accessext/content/listofaccesskeys.xul";
	      break;
	      case 'listofdhtml':
	      case 'ariawidget':
	      case 'accessext-form-list-dhtml':
	         id = "accessext-form-list-dhtml";
	         url = "chrome://accessext/content/listofdhtml.xul";
	      break;      
	      case 'listofdhtmllog':
	      case 'accessext-form-list-dhtmllog':
	         id = "accessext-form-list-dhtmllog";
	         url = "chrome://accessext/content/listofdhtmllog.xul";
	      break;            
	      case 'listofdhtmlrelationships':
	      case 'ariarelationships':
	       case 'accessext-form-list-dhtmlrelationships':
	         id = "accessext-form-list-dhtmlrelationships";
	         url = "chrome://accessext/content/listofdhtmlrelationships.xul";
	      break;            
	      case 'listofdhtmlrdfroles':
	      case 'accessext-form-list-dhtmlrdfroles':
	         id = "accessext-form-list-dhtmlrdfroles";
	         url = "chrome://accessext/content/listofdhtmlrdfroles.xul";
	      break;
	      case 'listofmapelements':
	      case 'navigation':
	      case 'accessext-form-list-navLists':
	         id = "accessext-form-list-navLists";
	         url = "chrome://accessext/content/listofnavlists.xul";
	      break;
	      case 'listofforms':
	      case 'forms':
	      case 'accessext-form-list-forms':
		     id = "accessext-form-list-forms";
	         url = "chrome://accessext/content/listofforms.xul";
	      break;
	      case 'listofframes':
	      case 'frames':
	      case 'accessext-form-list-frames':
	         id = "accessext-form-list-frames";
	         url = "chrome://accessext/content/listofframes.xul";
	      break;
	      case 'listofimages':
	      case 'images':
	      case 'accessext-form-list-images':
	         id = "accessext-form-list-images";
	         url = "chrome://accessext/content/listofimages.xul";
	      break;
	      case 'listofevents':
	      case 'events':
	      case 'accessext-form-list-events':
	         id = "accessext-form-list-events";
	         url = "chrome://accessext/content/listofevents.xul";
	      break;
	      case 'listofdatatables':
	      case 'datatables':
	      case 'accessext-form-list-datatables':
	         id = "accessext-form-list-datatables";
	         url = "chrome://accessext/content/listofdatatables.xul";
	      break;
	      case 'about':
	         id = "accessext-about";
	         url = "chrome://accessext/content/about.xul";
	      break;
	      case 'issues':
	      case 'accessext-issues':
	         id = "accessext-issues";
	         url = "chrome://accessext/content/issuesummary.xul";
	      break;
	      case 'title':
	      case 'titles':
	      case 'accessext-title':
	         id = "accessext-title";
	         url = "chrome://accessext/content/title.xul";
	      break;
	      case 'colorcontrast':
	      case 'accessext-colorcontrast':
	         id = "accessext-colorcontrast";
	         url = "chrome://accessext/content/contrast.xul";
	      break;
	      case 'textflow':
	      case 'accessext-textflow':
	         id = "accessext-textflow";
	         url = "chrome://accessext/content/textflow.xul";
	      break;
	      case 'textsizing':
	      case 'accessext-textsizing':
	         id = "accessext-textsizing";
	         url = "chrome://accessext/content/textsizing.xul";
	      break;
	      case 'textstyling':
	      case 'accessext-textstyling':
	         id = "accessext-textstyling";
	         url = "chrome://accessext/content/textstyling.xul";
	      break;
	      case 'contentpositioning':
	      case 'layoutTables':
	      case 'accessext-contentpositioning':
	         id = "accessext-contentpositioning";
	         url = "chrome://accessext/content/contentpositioning.xul";
	      break;
	      case 'lists':
	      case 'accessext-lists':
	         id = "accessext-lists";
	         url = "chrome://accessext/content/lists.xul";
	      break;
	      case 'abbr':
	      case 'accessext-form-list-abbr':
	         id = "accessext-form-list-abbr";
	         url = "chrome://accessext/content/listofabbr.xul";
	      break;
	      case 'listofimagemaps':
	      case 'imagemaps':
	      case 'accessext-form-list-imagemaps':
	         id = "accessext-form-list-imagemaps";
	         url = "chrome://accessext/content/listofimagemaps.xul";
	      break;
	      case 'listofobjects':
	      case 'object':
	      case 'accessext-form-list-objects':
	         id= "accessext-form-list-objects";
	         url = "chrome://accessext/content/listofobjects.xul";
	      break;
	      case 'listoflanguage':
	      case 'languages':
	      case 'accessext-form-list-languages':
	         id= "accessext-form-list-languages";
	         url = "chrome://accessext/content/listoflang.xul";
	      break;
	      case 'w3cspec':
	      case 'w3c':
	      case 'accessext-w3cspec':
	         id = "accessext-w3cspec";
	         url = "chrome://accessext/content/w3cspec.xul";
	      break;
	      case 'faeconfig':
	         id = "accessext-faeconfig";
	         url = "chrome://accessext/content/faeConfig.xul";
	      break;
	      default:
	         return false;
	      
	   }
	   AE.accessext_openWindows[AE.accessext_openWindows.length] = window.openDialog(url,id,style);
	   return true;
	},
	
	accessext_handle_options_accesskeys: function() {
	   var prefs = getAccessextPrefService();
	   prefs.setBoolPref("accesskeycausesactivation", accessext_isChecked("accessext-toolbarbutton-accesskeys-disable"));
	},
	
	accessext_handle_options_saveSettings: function() {
	   var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
	   prefs.savePrefFile(null);
	},
	
	//
	// Much of the code below is heavily borrowed from the Web Developer plugin
	//    by Chris Pederick and is available at
	//    http://www.chrispederick.com/work/firefox/webdeveloper/
	//
	
	accessext_dumpUserAgent: function() {
	   for (var a in navigator) {
	      accessext_consoleDump('navigator.' + a + '=' + navigator[a]);
	   }
	},
	
	// View page information
	accessext_handle_list_pageInfo: function() {
	   var chromeLocation= (accessext_is_firefox() ?
	      "chrome://browser/content/pageInfo.xul" :
	      "chrome://navigator/content/pageInfo.xul");
	   window.openDialog(chromeLocation, "accessext-page-information-dialog", "chrome, close", window.content.document);
	},
	
	// From http://www.xulplanet.com/references/xpcomref/ifaces/nsIWindowMediator.html#method_getEnumerator
	// returns an array of all html documents across all windows of this process, 
	// ... except for those whose URL begins with "chrome://" (it was also returning the Venkman debugger)
	accessext_getAllHtmlDocuments: function() {
	   var htmlDocuments = new Array();
	
	   var windowMediator = 
	      Components.classes["@mozilla.org/appshell/window-mediator;1"].
	      getService(Components.interfaces.nsIWindowMediator);
	   var winEnum = windowMediator.getXULWindowEnumerator(null);
	   
	   while (winEnum.hasMoreElements()) {
	      var win = winEnum.getNext();
	      if(!(win instanceof Components.interfaces.nsIXULWindow)) {
	         continue;
	      }
	      
	      var docShellEnum = win.docShell.getDocShellEnumerator(
	         Components.interfaces.nsIDocShellTreeItem.typeAll, 
	         Components.interfaces.nsIDocShellTreeItem.ENUMERATE_FORWARDS);
	      while(docShellEnum.hasMoreElements()) {
	         var docShell = docShellEnum.getNext();
	         if(docShell instanceof Components.interfaces.nsIDocShell) {
	            var domDocument = docShell.contentViewer.DOMDocument;
	            if(domDocument instanceof HTMLDocument) {
	               // Test to make sure we're not picking up some chrome window
	               if(!(new RegExp("^chrome://").test(domDocument.URL))) {
	                  htmlDocuments.push(domDocument);
	               }
	            }
	         }
	      }
	   }
	   return htmlDocuments;
	},
	
	// checkAction is "toggle" or a boolean describing the state of the feature on theDoc
	// exec is if you want the callback to execute (you usually do)
	// theDoc is the document or an array of docuemnts you want the callback to execute on
	accessext_toggle_feature: function(feature,checkAction,exec,theDoc) {
	   var id = false;
	   var element;
	   var func;
	   var pref = false;
	   var checkStatus; 
	   var doc = null;
	   var accessext_features = new AccessibilityExtension.LIB.accessextFeatures();
	   
	   try {
	      if (accessext_features.featureAvailable(feature)) {
	         var f = accessext_features.getFeature(feature);
	         
	         if (f) {
	            if(checkAction == 'toggle') {
	               checkStatus = (f.getToggleStatus() == false);
	            } else {
	               // assume it's boolean meant to describe the status to be of the feature
	               checkStatus = checkAction;
	            }
	            var shouldCall = true;
	            if(typeof exec != "undefined") {
	               if(exec != null) {
	                  shouldCall = exec;
	               }
	            }
	/*
	// romanows, 6/23/06: I think this is meant to be a sanity check; but it's screwing up the actual operation when you set a global preference on another tab/window.
	            if (!checkStatus && accessext_getActivePreferenceMode() == 'global' && !accessext_activeDoc.hasPref(f.prefStr)) {
	//             accessext_consoleDump('Tried to disable ' + feature + ' but it was not there in the first place');
	               shouldCall = false;
	            }
	*/
	            if(typeof theDoc != "undefined") {
	               doc = new Array();
	               doc = doc.concat(theDoc);  
	            }
	
	            if (shouldCall) {
	               if(accessext_getActivePreferenceMode() == 'global' && doc == null) {
	                  // perform the feature callback on every document
	                  var allDocuments = accessext_getAllHtmlDocuments();
	                  f.callback(checkStatus,allDocuments);  
	               } else {
	                  // only perform the feature callback on what was passed in (or, often, the current page when doc was not passed)
	                  //accessext_consoleDump('Switching feature ' + feature + ' to ' + (checkStatus ? 'on' : 'off'));
	                  f.callback(checkStatus,doc);           
	               }
	            }
				
	            accessext_addInitialSetting(feature, f, doc, shouldCall);
	            f.updateToggle(checkStatus);
				if (accessext_activeDoc != null) {
					accessext_activeDoc.setBoolPref(f.prefStr,checkStatus);
				}
				
	            return true;
	         } else {          
	         }
	      }
	   } catch (e) {
	      accessext_consoleDump('accessext_toggle_feature: exception: ', e);
	      return false;
	   }
	   return true;
	},
	
	accessext_addInitialSetting: function(settingName, feature, docs, shouldCall) {   
	   //if the initial settings have not already been recorded
	   if(!accessext_initialSettingsHash.hasOwnProperty(settingName)) {
	     var setting = new Object();
	      
	      setting['Feature'] = feature;
	      setting['Docs'] = docs;
	      setting['ShouldCall'] = shouldCall;
	      accessext_initialSettingsHash[settingName] = setting;
	//  accessext_consoleDump('settingName = ' + settingName + ' addInitialSetting initial setting = ' + setting.Feature.initialState);
	   }
	},
	
	/**
	 * Reset the check on the menu to their default settings. Since author-css-enabled, css-tags-enabled, and css-tables-enabled
	 * need to remember their settings between sessions yet the default it set to true they need special handling, this
	 * this whil they are handled outside of the accessext_initialSettingsHash loop. (i.e. they are not elements of accessext_initialSettingsHash)
	 * @return nothing
	 * @author Sandy Foltz (as of 8/07)
	*/
	
	accessext_cmd_about_reset: function() {
	   for(var settings in accessext_initialSettingsHash) {
	      var setting = accessext_initialSettingsHash[settings];
	      var feature = setting['Feature'];
	      var initialState = feature.initialState;
	      var docs = setting['Docs'];
	      var shouldCall = setting['ShouldCall'];
	  
	  //accessext_consoleDump('settings = ' + settings + ' reset setting = ' + initialState);
	
	      if (shouldCall) {
	         if(accessext_getActivePreferenceMode() == 'global' && docs == null) {
	            // perform the feature callback on every document
	            var allDocuments = accessext_getAllHtmlDocuments();
	            feature.callback(initialState, allDocuments);
	            delete accessext_initialSettingsHash[settings]; 
	         } else {
	            feature.callback(initialState, docs);           
	         }
	      }
	      
	      feature.updateToggle(initialState);
	      accessext_activeDoc.setBoolPref(feature.prefStr,initialState);
	      
	   }  
	   //set the check marks
		accessext_toggle_feature('author-css-enabled',true,false,docs);
		accessext_toggle_feature('css-tags-enabled',true,false,docs);
		accessext_toggle_feature('css-tables-enabled',true,false,docs);
		var allDocsToDo = docs;
	    if(accessext_getActivePreferenceMode() == 'global') {
		    allDocsToDo = accessext_getAllHtmlDocuments();
		}
		//format the page(s) correctly
		accessext_handle_styles_css_enabled(true,allDocsToDo);
		accessext_handle_styles_css_tags_enabled(true,allDocsToDo);
		accessext_handle_styles_tables_enabled(true,allDocsToDo);
	   	
		//remove all remembered settings for widths (& heights) of dialogs, sidebars, & columns
	// Load lists from runtime prefs
	    var preferencesService = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("");
	    var runtimePrefs = preferencesService.getChildList("", {});
	    for (var i = 0; i < runtimePrefs.length; i++) {
			var name = runtimePrefs[i];
			try {
				if (name.indexOf('list-header-') >= 0) {
					//accessext_consoleDump('found col accessext_cmd_about_reset ' + name );
					preferencesService.clearUserPref(name);
				}
				if (name.indexOf('accessext-form-') >= 0) {
					//accessext_consoleDump('found dialog accessext_cmd_about_reset ' + name );
					preferencesService.clearUserPref(name);
				}
	        } catch(e) {
				accessext_consoleDump('accessext_cmd_about_reset ' + name + ' exception: ', ex);
			}
	   }
	},
	
	accessext_open_CITA: function() {
	   accessext_generatePage(accessext_getBundleSingleString('links.CITAHome'));
	},
	
	accessext_open_MozExtHelp: function() {
	   accessext_generatePage(accessext_getBundleSingleString('links.accessextHelp'));
	},
	
	accessext_open_MozExtHome: function() {
	   accessext_generatePage(accessext_getBundleSingleString('links.accessextHomepage'));
	},
	
	accessext_open_BugReport: function() {
	   accessext_generatePage(accessext_getBundleSingleString('links.bugtrack'));
	},
	
	accessext_open_TestPages: function() {
	   accessext_generatePage(accessext_getBundleSingleString('links.testpages'));
	},
	
	accessext_open_FAE: function() {
	   accessext_generatePage(accessext_getBundleSingleString('links.FAE'));
	},
	
	accessext_open_WebAIM: function() {
	   accessext_generatePage(accessext_getBundleSingleString('links.WebAIM'));
	},
	
	accessext_open_Cynthia: function() {
	   accessext_generatePage(accessext_getBundleSingleString('links.Cynthia'));
	},
	
	accessext_open_ATRC: function() {
	   accessext_generatePage(accessext_getBundleSingleString('links.ATRC'));
	},
	
	accessext_open_TAW: function() {
	   accessext_generatePage(accessext_getBundleSingleString('links.TAW'));
	},
	
	/** Opens a new page that informs the user if their extension version is up-to-date.
	 * This calls a URL with passed version information and let's the server-side PHP script let the user know the extension's status.
	 * @returns None
	 */
	// no longer used - updates are done automatically when you submit a new addon to the addon site
	accessext_open_CheckUpdates: function() {
	   var sbSrv  = Components.classes['@mozilla.org/intl/stringbundle;1'].createInstance();
	   var sbSrvI   = sbSrv.QueryInterface(Components.interfaces.nsIStringBundleService);
	   bundle_about=sbSrvI.createBundle("chrome://accessext/locale/version.properties");
	   var versionBundle=document.getElementById("bundle_version");
	   var versionMajor = versionBundle.getString("version.major");
	   var versionMinor = versionBundle.getString("version.minor");
	   var release = versionBundle.getString("version.release");
	   var build = versionBundle.getString("version.build");
	   var versionString = versionMajor+"."+versionMinor+"."+release+"."+build;
	      
	   accessext_generatePage(accessext_getBundleSingleString('links.updateCheck')+'?version='+versionString);
	},
	
	accessext_handle_export_keybindings: function() {
	   accessextKeyboardBindingsExport();
	},
	
	accessext_handle_import_keybindings: function() {
	   accessextKeyboardBindingsImport();
	},
	
	accessext_handle_keyboardNavEnabled: function(checked) {
	   var prefStr = "keyboardnav.enabled";
	   var typeAheadBackup = "keyboardnav.typeaheadWasOn";
	   var prefs = getAccessextPrefService();
	   prefs.setBoolPref(prefStr, checked);
	   var typeAhead;
	   if (checked) {
	      try {
	         prefs.unlockPref("typeaheadfind");
	         typeAhead = prefs.getBoolPref("typeaheadfind");
	      } catch (e) {
	         // The preference wasn't there, but do we care?
	      }
	      prefs.setBoolPref(typeAheadBackup,typeAhead);
	      prefs.setBoolPref("typeaheadfind",false);
	   } else {
	      try {
	         typeAhead = prefs.getBoolPref(typeAheadBackup);
	      } catch (e) {
	         // The preference wasn't there, but do we care?
	      }
	      prefs.setBoolPref("accessibility.typeaheadfind",typeAhead);
	   }
	},
	
	accessext_handle_showMenus: function() {
	   var prefStr = "showmenus";
	   var prefs = getAccessextPrefService();
	   var showMenus = true;
	   if (prefs.prefHasUserValue(prefStr)) {
	      showMenus = prefs.getBoolPref(prefStr);
	   }
	   
	   var accessextMenu = document.getElementById("accessext-menu");
	   //var navMenu = document.getElementById("accessext-mainmenu-navigation");
	
	   //if (accessextMenu && navMenu) {
	   if (accessextMenu) {
	      accessextMenu.hidden = !showMenus;
	      //navMenu.hidden = !showMenus;
	   }
	   
	   var bcast = document.getElementById("accessext-bcast-options-showmenus");
	   if (bcast) {
	      bcast.checked = showMenus;
	   }
	},
	
	accessext_toggle_showmenus: function() {
	   var prefStr = "showmenus";
	   var prefs = getAccessextPrefService();
	   var showMenus = true;
	   if (prefs.prefHasUserValue(prefStr)) {
	      showMenus = prefs.getBoolPref(prefStr);
	   }
	   showMenus = !showMenus; 
	
	   prefs.setBoolPref(prefStr,showMenus);
	   accessext_handle_showMenus();
	},
	
	accessext_switchPrefPersistenceMode: function(mode) {
	   var prefs = getAccessextPrefService();
	   //Hard coded values for now
	   var global = document.getElementById("accessext-bcast-options-prefPersistence-document").getAttribute("checked");
	   var broadcasters = new Object();
	   broadcasters['document'] = 'accessext-bcast-options-prefPersistence-document';
	   broadcasters['tab'] = 'accessext-bcast-options-prefPersistence-tab';
	   broadcasters['global'] = 'accessext-bcast-options-prefPersistence-global';
	   
	   switch (mode) {
	      case 'document':
	         //accessext_consoleDump('switching to document mode');
	      break;
	      case 'tab':
	         //accessext_consoleDump('switching to tab mode -- unimplemented');
	      break;
	      case 'global':
	         //accessext_consoleDump('switching to global mode');
	      break;
	      default:
	         alert('Invalid selection for preference persistence: ' + mode);
	         return;
	   }
	   
	   prefs.setCharPref("options.prefPersistence",mode);
	    
	   for (var a in broadcasters) {
	      var bc = document.getElementById(broadcasters[a]);
	      bc.setAttribute('checked', (a == mode) ? 'true' : 'false');
	      //accessext_consoleDump('switching toggle for ' + broadcasters[a] + ' to ' + bc.getAttribute('checked'));
	   }
	},
	
	accessext_switchPrefStandard: function(mode) {
	   var oldStd = currStandard();
	   var prefs = getAccessextPrefService();
	   
	   var bc = document.getElementById('accessext-bcast-options-prefStandard-icita07');
	   bc.setAttribute('checked', ('icita07' == mode) ? 'true' : 'false');
	   bc = document.getElementById('accessext-bcast-options-prefStandard-aria');
	   bc.setAttribute('checked', ('aria' == mode) ? 'true' : 'false');
	   bc = document.getElementById('accessext-bcast-options-prefStandard-icita08');
	   bc.setAttribute('checked', ('icita08' == mode) ? 'true' : 'false');
	
	   prefs.setCharPref("options.prefStandard", mode);
	    
	   if (mode != oldStd) {
	      savePreferences(mode);
	   }
	},
	savePreferences: function(newSetting) {
		try {
			//choosestandard - set which std is visible in the saved colums headers
		    var preferencesService = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("");
		    var runtimePrefs = preferencesService.getChildList("", {});
		    for (var i = 0; i < runtimePrefs.length; i++) {
				var name = runtimePrefs[i];
				try {
					if (name.indexOf('accessext') >= 0 && name.indexOf('showColumns') >= 0) {
			  			if (preferencesService.prefHasUserValue(name)) {
							var prefVal = preferencesService.getCharPref(name);
							preferencesService.setCharPref(name,prefVal.replace(/(icita07)|(aria)|(icita08)/g, newSetting));
						}
					}
		        } catch(e) {
					accessext_consoleDump('chooseStandard exception: ', e);
				}
		   }	
			
			// show the only the selected standard in the open dialogs/side bars
			var dlgName;
			var accessWin = AE; //window; //window.opener;
			var l = AE.accessext_openWindows.length
			for (var i=0; i<l; i++) {
				var dialgWin = AE.accessext_openWindows[i];
				if (dialgWin.accessext_openWindows) {
					var subWinCount = dialgWin.accessext_openWindows.length;
					for (var subWinIndex=0; subWinIndex<subWinCount; subWinIndex++) {
						var subWin = dialgWin.accessext_openWindows[subWinIndex];
						//subWin.postMessage("differentStandard");
						dlgName = subWin.name;
						subWin.close();	
						accessext_open_window(dlgName)
					}
				} 
				//dialgWin.postMessage("differentStandard", "*");	
				dlgName = dialgWin.name;
				dialgWin.close();	
				accessext_open_window(dlgName)
			}
			//accessWin.sidebar.postMessage("differentStandard");
			dlgName = window.sidebar.name;
			/* Note that the reload calls accessext_saveDialogPrefs, which saves the current
			 * setting overwriting the new 'Rule Set'.
			 */
			window.sidebar.location.reload();	//reload, refresh location only available if sidebar was open on loading browser
			accessext_open_window(dlgName)
		} catch (ex) {
			accessext_consoleDump('savePreferences exception: ', ex);
		}
	},
	
	accessext_handle_standards_useDom: function(checked) {
	   //This needs to flip the value of accessext-bcast-standards-supportsDom broadcaster
	   var bc = document.getElementById('accessext-bcast-standards-supportsDom');
	   if (bc) {
	      bc.setAttribute('disabled',checked ? 'true' : 'false');
	   }
	},
	
	
	accessext_handle_standards_newWindow: function(checked) {
	   //Does nothing right now. Other methods will check the value
	}
	
});
}});	